
#include "hw2_syscalls.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/resource.h>
#include <errno.h>
#include <sys/resource.h>

#define NUM_OF_SWITCH_INFO 150

/** calculates the n'th fibonaci number */

int fibonaci(int n) {

   if(n < 2)
       return n;

	return fibonaci(n-1) + fibonaci(n-2);
}


/** printing the random params */

int checkValidNice(int nice) {

	//TODO: check if those are the right boundries of nice.
	if(nice > 19 || nice < -20) {
		return 0;
	}

	return 1;

}
void printRandParams(struct random_params params) {

	printf("random params are: \n\n");
	printf("p_prio = %d\n", params.p_prio);
	printf("p_epoch = %d\n", params.p_epoch);
	printf("p_interactive = %d\n", params.p_interactive);
}

/** prints statistics using info and params on task with the given pid **/

void printStats(struct switch_info info) {

  printf("previous: %d  ", info.previous_pid);
  printf("next: %d  ", info.next_pid);
  printf("previous prio: %d  ", info.previous_priority);
  printf("next prio: %d ", info.next_priority);
  printf("best task priority: %d  ", info.best_priority);

  printf("is new epoch? ");
  if(info.is_new_epoch) {
	  printf("Yes.  ");
  }
  else {
	  printf("No.   ");
  }

  printf("time of switching: %lu\n", info.time);

  /** checks what is the reason for switching. */
  printf("reason: ");
  switch(info.reason) {
    case TASK_FORKED: printf("NEW TASK WAS CREATED."); break;
    case TASK_EXIT: printf("THE TASK ENDED."); break;
    case TASK_YIELD: printf("THE TASK YIELDED."); break;
    case TASK_WAITING: printf("THE TASK GOES OUT FOR WAITING."); break;
    case TASK_WAKEUP: printf("TASK WITH HIGHER PRIORITY RETURNS FROM WAITING."); break;
    case TASK_TIME_ENDED: printf("THE TIME SLICE OF THE TASK ENDED."); break;
	default: printf("DEFAULT TASK"); break;
  }
  printf("\n\n");

}

int main(int argc, char** argv) {
	int mode_result, i, num_of_records, task_pid, t_nice, t_num, curr_pid;
	int curr_prio, best_prio = -1;
	struct random_params rp;
    struct switch_info s_info[NUM_OF_SWITCH_INFO];
    int prio, epoch , interactive;

	if(argc < 6 || argc%2 != 0) {
		perror("Number of params is illegal.");
		exit(-1);
	}

    prio=atoi(argv[1]);
    epoch=atoi(argv[2]);
    interactive=atoi(argv[3]);

	if(prio < 1 || epoch < 1 || interactive < 1
		|| prio > 100 || epoch > 100 || interactive> 100 ) {
		perror("Illegal params.");
		exit(-1);
	}

	rp.p_prio = prio;
	rp.p_epoch = epoch;
	rp.p_interactive = interactive;

	mode_result = sched_setmechanism(MODE_RANDOM, &rp);
	if(mode_result == -1) {
		perror("problem with sched_setmechanism random.");
		exit(-1);
	}

	mode_result = sched_getmechanism(&rp);
	if(mode_result == -1) {
		perror("problem with sched_getmechanism random.");
		exit(-1);
	}

	if(mode_result != MODE_RANDOM || rp.p_prio!=prio  || rp.p_epoch!=epoch || rp.p_interactive!=interactive) {
		printf("changing mode to mode random failed.");
	}

	/** creating tasks using forks */
	for(i = 4; i < argc; i+=2) {

	  t_nice = atoi(argv[i]);
	  t_num = atoi(argv[i+1]);
	  if(!checkValidNice(t_nice)) {
		  perror("Invalid value for nice of param number.");
		  exit(-1);
	  }

	  /** creating tasks with fork and executing fibonaci */
      task_pid = fork();

      if(task_pid < 0) {
    	  perror("fork failed.");
    	  exit(-1);
      }

      if(task_pid == 0) {
    	  int curr_pid = getpid();
    	  setpriority(PRIO_PROCESS, 0, t_nice);
          fibonaci(t_num);
          printf("is process with pid %d interactive? ", curr_pid);
          if(is_interactive(curr_pid)) {
        	  printf("Yes.\n\n");
          }
          else {
        	  printf("No.\n\n");
          }

          curr_prio = get_cur_running_priority(&best_prio);
          printf("priority of task with pid %d is: %d \n", curr_pid, curr_prio);
      }

      if(task_pid > 0) {
    	  setpriority(PRIO_PROCESS, task_pid, t_nice);
      }

	}

    num_of_records = get_scheduling_statistic(s_info);
    for(i = 0; i < num_of_records; i++) {
    	printf("switch number %d: \n", i);
    	printStats(s_info[i]);
    }

    sched_setmechanism(MODE_REGULAR, NULL);

    mode_result = sched_getmechanism(&rp);
    if(mode_result != MODE_REGULAR) {
		printf("changing mode to mode regular failed.\n\n");
	}

	exit(0);
}
